// Renderer.h
//
#ifndef RENDERER_ONCE
#define RENDERER_ONCE

#include <string>
#include "Color.h"
#include "Math.h"
#include "Box.h"
#include "Selection.h"
#include "FloatingOrigin.h"
#include "TextRenderer.h"

namespace OpenGL{

class Font;

class Renderer
{
private:
	Color bkTop;
	Color bkBottom;
	bool _useGradient;

	double _zoomFactor;
	Math::dvec3 _center;
	Math::dmat4 _projectionMatrix;
	Math::dmat4 _modelViewMatrix;
	Math::ivec4 _viewport;
	Math::box3  _viewBox;
	Math::box3  _sceneBox; // viewable area (world space)
	Selection   _selection;
	
	Font           *fonts;
	
	FloatingOrigin _origin;
	TextRenderer   _textRenderer;

	void updateViewBox();

public:
	Renderer();
	~Renderer();

	void begin2D();
	void end2D();

	void setClearColor(const Color &flatColor );
	void setClearColor(const Color &gradientTop, const Color &gradientBottom );	

	void clearBackground();

	Math::dvec3 convertWindowTo3D(int x, int y, bool flipY = true );
	Math::dvec2 convertWindowTo2D(int x, int y, bool flipY = true );
	Math::dvec3 convertWorldToWindow(const Math::dvec3 &p, bool flipY = true );
	Math::dvec3 convertWorldToWindow(const Math::dvec2 &p, bool flipY = true );
	Math::box3  convertWorldToWindow(const Math::box3 &b, bool flipY = true );
	int	 convertSizeToPixels(double distance);
	
	void openSelectionMode(int x, int y);
	std::vector<unsigned int> getSelectionNames( Selection::SelectionMode mode = Selection::Nearest);
	void closeSelectionMode();
	bool selectionFailed() const;

	void setViewport(int x, int y, int w, int h );
	void setProjectionMatrix();
	void setViewMatrix(const Math::dvec3 &eye, const Math::dvec3 &center,const Math::dvec3 &up );
	void setRTCMatrix( const Math::dvec3 &center );
	void storeModelView();

	void enableFloatingOrigin( bool on = true );
	void setCenter(const Math::dvec3 &c);
	void setSceneBox( const Math::box3 &b );
	void setZoom( double zoomValue );
	void zoomInOut( double step, const Math::dvec3 &target );
	void fitView( const Math::box3 &box = Math::box3() );
	
	void setFont( Font *f );
	Font *getFont() {return fonts; }

	void drawText();
	void addText( const Math::dvec3 &pos, const std::string &text, const Color &color, double size = 12.0, TextRenderer::TextAlignment alignment = TextRenderer::AlignLeft );
	
	double     worldSize() const;
	double	   pixelToWorldSize( float pixels ) const;
	int        worldSizeToPixels( double worldSize ) const;
	bool       isVisible( const Math::dvec3 &p ) const;
	bool       isVisible( const Math::box3  &b ) const;
	
	bool isFloatingOriginEnabled()	const   { return _origin.isEnabled(); }
	Math::dvec3 center()			const	{ return _center; }
	Math::dvec3 origin()			const	{ return _origin.get(); }
	Math::box3  viewBox()		    const   { return _viewBox; }
	Math::ivec4 viewport()			const   { return _viewport; }
	Math::box3  worldBox()			const	{ return _viewBox.translated(_center); }
	Math::box3  sceneBox()          const   { return _sceneBox; }
	double      zoomFactor()	    const   { return _zoomFactor; }

	// -----------------------------------------------------------------------------------------------
	void glVertex2( const Math::vec2 &v );
	void glVertex3( const Math::vec3 &v );
	
	void glVertex2( const Math::dvec2 &v );
	void glVertex3( const Math::dvec3 &v );
	
	void glVertex2( const Math::ivec2 &v );
	void glVertex3( const Math::ivec3 &v );
};


}

#endif